<!DOCTYPE html>
<!-- saved from url=(0041)http://c.biancheng.net/view/vip_7082.html -->
<html lang="zh-CN"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><script type="text/javascript" async="" charset="utf-8" src="./12.8Java高级应用之通过反射操作泛型_files/core.php"></script>

<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面，任何其他内容都*必须*跟随其后！ -->
<!-- 启用Chromium高速渲染模式 -->
<meta name="renderer" content="webkit">
<meta name="force-rendering" content="webkit">
<!-- 禁止百度转码 -->
<meta name="applicable-device" content="pc,mobile">
<meta name="MobileOptimized" content="width">
<meta name="HandheldFriendly" content="true">
<meta http-equiv="Cache-Control" content="no-transform">
<meta http-equiv="Cache-Control" content="no-siteapp">
<!-- 禁止识别电话号码 -->
<meta name="format-detection" content="telephone=no">

<link rel="shortcut icon" href="http://c.biancheng.net/favicon.ico?v=1.6.72">
<link href="./12.8Java高级应用之通过反射操作泛型_files/common.css" rel="stylesheet">
<title>Java高级应用之通过反射操作泛型</title>
<meta name="description" content="学习完《 Java泛型详解 》一节中我们了解到，从Java 1.5 版本开始，Java 的 Class 类增加了泛型功能，从而允许使用泛型来限制 Class 类。例如，String.class 的类型实际上是 ClassString。如果 C">
</head>
<body>
<div id="topbar" class="clearfix">
	<ul id="product-type" class="left">
		<li>
			<a href="http://c.biancheng.net/"><span class="iconfont iconfont-home"></span>首页</a>
		</li>
		<li class="active">
			<a href="http://c.biancheng.net/sitemap/" rel="nofollow"><span class="iconfont iconfont-book"></span>教程</a>
		</li>
		<li>
			<a href="http://vip.biancheng.net/p/vip/show.php" rel="nofollow" target="_blank"><span class="iconfont iconfont-vip"></span>VIP会员</a>
		</li>
		<li>
			<a href="http://vip.biancheng.net/p/q2a/show.php" rel="nofollow" target="_blank"><span class="iconfont iconfont-q2a"></span>一对一答疑</a>
		</li>
		<li>
			<a href="http://fudao.biancheng.net/" rel="nofollow" target="_blank"><span class="iconfont iconfont-fudao"></span>辅导班</a>
		</li>
	</ul>
</div>
<div id="header" class="clearfix">
	<a id="logo" class="left" href="http://c.biancheng.net/">
		<img height="26" src="./12.8Java高级应用之通过反射操作泛型_files/logo.png" alt="C语言中文网">
	</a>
	<ul id="nav-main" class="hover-none left clearfix">
		<li class="wap-yes"><a href="http://c.biancheng.net/">首页</a></li>
		<li><a href="http://c.biancheng.net/c/">C语言教程</a></li>
		<li><a href="http://c.biancheng.net/cplus/">C++教程</a></li>
		<li><a href="http://c.biancheng.net/python/">Python教程</a></li>
		<li><a href="http://c.biancheng.net/java/">Java教程</a></li>
		<li><a href="http://c.biancheng.net/linux_tutorial/">Linux入门</a></li>
		<li><a href="http://c.biancheng.net/sitemap/" title="网站地图">更多&gt;&gt;</a></li>
	</ul>
	<span id="sidebar-toggle" class="toggle-btn" toggle-target="#sidebar">目录 <span class="glyphicon"></span></span>

	<a href="http://vip.biancheng.net/?from=topbar" class="user-info glyphicon glyphicon-user hover-none" target="_blank" rel="nofollow" title="用户中心"></a>
</div>
<div id="main" class="clearfix">
	<div id="sidebar" class="toggle-target">
	<div id="contents">
		<dt><span class="glyphicon glyphicon-option-vertical" aria-hidden="true"></span><a href="http://c.biancheng.net/java/">Java教程</a></dt>
		
			<dd>
				<span class="channel-num">1</span>
				<a href="http://c.biancheng.net/java/10/">Java入门基础及环境搭建</a>
			</dd>
		
			<dd>
				<span class="channel-num">2</span>
				<a href="http://c.biancheng.net/java/20/">Java程序设计基础</a>
			</dd>
		
			<dd>
				<span class="channel-num">3</span>
				<a href="http://c.biancheng.net/java/30/">Java流程控制语句</a>
			</dd>
		
			<dd>
				<span class="channel-num">4</span>
				<a href="http://c.biancheng.net/java/40/">Java字符串处理</a>
			</dd>
		
			<dd>
				<span class="channel-num">5</span>
				<a href="http://c.biancheng.net/java/50/">Java数字和日期处理</a>
			</dd>
		
			<dd>
				<span class="channel-num">6</span>
				<a href="http://c.biancheng.net/java/60/">Java内置包装类</a>
			</dd>
		
			<dd>
				<span class="channel-num">7</span>
				<a href="http://c.biancheng.net/java/70/">Java数组处理</a>
			</dd>
		
			<dd>
				<span class="channel-num">8</span>
				<a href="http://c.biancheng.net/java/80/">Java类和对象</a>
			</dd>
		
			<dd>
				<span class="channel-num">9</span>
				<a href="http://c.biancheng.net/java/90/">Java继承和多态</a>
			</dd>
		
			<dd>
				<span class="channel-num">10</span>
				<a href="http://c.biancheng.net/java/100/">Java异常处理</a>
			</dd>
		
			<dd>
				<span class="channel-num">11</span>
				<a href="http://c.biancheng.net/java/110/">Java集合、泛型和枚举</a>
			</dd>
		<dd class="this"> <span class="channel-num">12</span> <a href="http://c.biancheng.net/java/120/">Java反射机制</a> </dd><dl class="dl-sub"><dd>12.1 <a href="http://c.biancheng.net/view/6907.html">Java反射机制的基本概念</a></dd><dd>12.2 <a href="http://c.biancheng.net/view/6909.html">Java反射机制API</a></dd><dd>12.3 <a href="http://c.biancheng.net/view/1109.html">Java通过反射访问构造方法</a></dd><dd>12.4 <a href="http://c.biancheng.net/view/1111.html">Java通过反射访问方法</a></dd><dd>12.5 <a href="http://c.biancheng.net/view/1112.html">Java通过反射访问成员变量</a></dd><dd>12.6 <a href="http://c.biancheng.net/view/1115.html">Java在远程方法中使用反射机制</a></dd><dd>12.7 <a href="http://c.biancheng.net/view/vip_7083.html">Java高级应用之通过反射访问操作数组</a><span class="glyphicon glyphicon-usd"></span></dd><dd class="active">12.8 <a href="http://c.biancheng.net/view/vip_7082.html">Java高级应用之通过反射操作泛型</a><span class="glyphicon glyphicon-usd"></span></dd></dl>
			<dd>
				<span class="channel-num">13</span>
				<a href="http://c.biancheng.net/java/130/">Java输入/输出流</a>
			</dd>
		
			<dd>
				<span class="channel-num">14</span>
				<a href="http://c.biancheng.net/java/java/135/">Java注解</a>
			</dd>
		
	</div>
</div>
	<div id="article-wrap">
		<div id="article">
			<div class="arc-info">
	<span class="position"><span class="glyphicon glyphicon-map-marker"></span> <a href="http://c.biancheng.net/">首页</a> &gt; <a href="http://c.biancheng.net/java/">Java教程</a> &gt; <a href="http://c.biancheng.net/java/120/">Java反射机制</a></span>
	<span class="read-num">阅读：2,670</span>
</div>

<div id="ad-position-bottom"></div>
			<h1>Java高级应用之通过反射操作泛型</h1>
			<div class="pre-next-page clearfix">
                    <span class="pre left"><span class="icon">&lt;</span> <span class="text-brief text-brief-pre">上一页</span><a href="http://c.biancheng.net/view/vip_7083.html">Java高级应用之通过反射访问操作数组</a></span>
                    <span class="next right"><a href="http://c.biancheng.net/java/130/">Java输入/输出流</a><span class="text-brief text-brief-next">下一页</span> <span class="icon">&gt;</span></span>
                </div>
			<div id="ad-arc-top"><p class="pic"></p><p class="text" adid="java-1v1q2a"><a href="http://c.biancheng.net/view/7552.html" target="_blank" style="color: #D33428;">C语言中文网推出辅导班啦，包括<span style="color: #008000;">「C语言辅导班、C++辅导班、算法/数据结构辅导班」</span>，全部都是一对一教学：一对一辅导 + 一对一答疑 + 布置作业 + 项目实践 + 永久学习。QQ在线，随时响应！</a></p></div>
			<div id="arc-body">学习完《<a href="http://c.biancheng.net/view/1085.html" target="_blank">Java泛型详解</a>》一节中我们了解到，从Java 1.5 版本开始，Java 的 Class 类增加了泛型功能，从而允许使用泛型来限制 Class 类。例如，String.class 的类型实际上是 Class&lt;String&gt;。如果 Class 对应的类暂时未知，则使用 Class&lt;?&gt;。通过在反射中使用泛型，可以避免使用反射生成的对象需要强制类型转换。<br>
<h2>
	泛型和 Class 类</h2>
使用 Class&lt;T&gt; 泛型可以避免强制类型转换。例如，下面提供一个简单的对象工厂，该对象工厂可以根据指定类来提供该类的实例。
<div class="snippet-container" style="undefined;"><div class="sh_bright snippet-wrap"><div class="snippet-menu sh_sourceCode" style="display: none;"><pre><a class="snippet-copy sh_url" href="http://c.biancheng.net/view/vip_7082.html#" style="display: none;">复制</a><a class="snippet-text sh_url" href="http://c.biancheng.net/view/vip_7082.html#">纯文本</a><a class="snippet-window sh_url" href="http://c.biancheng.net/view/vip_7082.html#">复制</a></pre></div><pre class="java sh_java snippet-formatted sh_sourceCode"><ol class="snippet-num"><li><span class="sh_keyword">public</span> <span class="sh_keyword">class</span><span class="sh_normal"> </span><span class="sh_classname">ObjectFactory</span> <span class="sh_cbracket">{</span></li><li>    <span class="sh_keyword">public</span> <span class="sh_keyword">static</span> <span class="sh_usertype">Object</span><span class="sh_normal"> </span><span class="sh_function">getInstance</span><span class="sh_symbol">(</span><span class="sh_usertype">String</span><span class="sh_normal"> </span>clsName<span class="sh_symbol">)</span> <span class="sh_cbracket">{</span></li><li>        <span class="sh_keyword">try</span> <span class="sh_cbracket">{</span></li><li>            <span class="sh_comment">// 创建指定类对应的Class对象</span></li><li>            <span class="sh_usertype">Class</span><span class="sh_normal"> </span>cls <span class="sh_symbol">=</span> Class<span class="sh_symbol">.</span><span class="sh_function">forName</span><span class="sh_symbol">(</span>clsName<span class="sh_symbol">);</span></li><li>            <span class="sh_comment">// 返回使用该Class对象创建的实例</span></li><li>            <span class="sh_keyword">return</span> cls<span class="sh_symbol">.</span><span class="sh_function">newInstance</span><span class="sh_symbol">();</span></li><li>        <span class="sh_cbracket">}</span> <span class="sh_keyword">catch</span> <span class="sh_symbol">(</span><span class="sh_usertype">Exception</span><span class="sh_normal"> </span>e<span class="sh_symbol">)</span> <span class="sh_cbracket">{</span></li><li>            e<span class="sh_symbol">.</span><span class="sh_function">printStackTrace</span><span class="sh_symbol">();</span></li><li>            <span class="sh_keyword">return</span> <span class="sh_keyword">null</span><span class="sh_symbol">;</span></li><li>        <span class="sh_cbracket">}</span></li><li>    <span class="sh_cbracket">}</span></li><li><span class="sh_cbracket">}</span></li></ol></pre><pre class="snippet-textonly sh_sourceCode" style="display:none;">public class ObjectFactory {
    public static Object getInstance(String clsName) {
        try {
            // 创建指定类对应的Class对象
            Class cls = Class.forName(clsName);
            // 返回使用该Class对象创建的实例
            return cls.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
</pre></div></div>
上面程序中第 5 、7 行代码根据指定的字符串类型创建了一个新对象，但这个对象的类型是 Object，因此当需要使用 ObjectFactory 的 getInstance() 方法来创建对象时，代码如下：<br>
<p class="info-box">
	// 获取实例后需要强制类型转换<br>
	Date d = (Date)ObjectFactory.getInstance("java.util.Date");</p>
或
<p class="info-box">
	JFrame f = (JFrame)ObjectFactory&nbsp;.getInstance("java.util.Date");</p>
上面代码在编译时不会有任何问题，但运行时将抛出 ClassCastException（强制类型转换异常），因为程序试图将一个 Date 对象转换成 JFrame 对象。<br>
<br>
如果将上面的 ObjectFactory 工厂类改写成使用泛型后的 Class，就可以避免这种情况。
<div class="snippet-container" style="undefined;"><div class="sh_bright snippet-wrap"><div class="snippet-menu sh_sourceCode" style="display:none;"><pre><a class="snippet-copy sh_url" href="http://c.biancheng.net/view/vip_7082.html#" style="display: none;">复制</a><a class="snippet-text sh_url" href="http://c.biancheng.net/view/vip_7082.html#">纯文本</a><a class="snippet-window sh_url" href="http://c.biancheng.net/view/vip_7082.html#">复制</a></pre></div><pre class="java sh_java snippet-formatted sh_sourceCode"><ol class="snippet-num"><li><span class="sh_keyword">public</span> <span class="sh_keyword">class</span><span class="sh_normal"> </span><span class="sh_classname">ObjectFactory2</span> <span class="sh_cbracket">{</span></li><li>    <span class="sh_keyword">public</span> <span class="sh_keyword">static</span> <span class="sh_symbol">&lt;</span>T<span class="sh_symbol">&gt;</span> <span class="sh_usertype">T</span><span class="sh_normal"> </span><span class="sh_function">getInstance</span><span class="sh_symbol">(</span><span class="sh_usertype">Class&lt;T&gt;</span><span class="sh_normal"> </span>cls<span class="sh_symbol">)</span> <span class="sh_cbracket">{</span></li><li>        <span class="sh_keyword">try</span> <span class="sh_cbracket">{</span></li><li>            <span class="sh_keyword">return</span> cls<span class="sh_symbol">.</span><span class="sh_function">newInstance</span><span class="sh_symbol">();</span></li><li>        <span class="sh_cbracket">}</span> <span class="sh_keyword">catch</span> <span class="sh_symbol">(</span><span class="sh_usertype">Exception</span><span class="sh_normal"> </span>e<span class="sh_symbol">)</span> <span class="sh_cbracket">{</span></li><li>            e<span class="sh_symbol">.</span><span class="sh_function">printStackTrace</span><span class="sh_symbol">();</span></li><li>            <span class="sh_keyword">return</span> <span class="sh_keyword">null</span><span class="sh_symbol">;</span></li><li>        <span class="sh_cbracket">}</span></li><li>    <span class="sh_cbracket">}</span></li><li><span style="display:none;">&nbsp;</span></li><li>    <span class="sh_keyword">public</span> <span class="sh_keyword">static</span> <span class="sh_type">void</span> <span class="sh_function">main</span><span class="sh_symbol">(</span>String<span class="sh_symbol">[]</span> args<span class="sh_symbol">)</span> <span class="sh_cbracket">{</span></li><li>        <span class="sh_comment">// 获取实例后无须类型转换</span></li><li>        <span class="sh_usertype">Date</span><span class="sh_normal"> </span>d <span class="sh_symbol">=</span> CrazyitObjectFactory2<span class="sh_symbol">.</span><span class="sh_function">getInstance</span><span class="sh_symbol">(</span>Date<span class="sh_symbol">.</span><span class="sh_keyword">class</span><span class="sh_symbol">);</span></li><li>        <span class="sh_usertype">JFrame</span><span class="sh_normal"> </span>f <span class="sh_symbol">=</span> CrazyitObjectFactory2<span class="sh_symbol">.</span><span class="sh_function">getInstance</span><span class="sh_symbol">(</span>JFrame<span class="sh_symbol">.</span><span class="sh_keyword">class</span><span class="sh_symbol">);</span></li><li>    <span class="sh_cbracket">}</span></li><li><span class="sh_cbracket">}</span></li></ol></pre><pre class="snippet-textonly sh_sourceCode" style="display:none;">public class ObjectFactory2 {
    public static &lt;T&gt; T getInstance(Class&lt;T&gt; cls) {
        try {
            return cls.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static void main(String[] args) {
        // 获取实例后无须类型转换
        Date d = CrazyitObjectFactory2.getInstance(Date.class);
        JFrame f = CrazyitObjectFactory2.getInstance(JFrame.class);
    }
}</pre></div></div>
在上面程序的 getInstance() 方法中传入一个 Class&lt;T&gt; 参数，这是一个泛型化的 Class 对象，调用该 Class 对象的 newInstance() 方法将返回一个 T 对象，如程序中第 4 行代码所示。接下来当使用 ObjectFactory2 工厂类的 getInstance() 方法来产生对象时，无须使用强制类型转换，系统会执行更严格的检查，不会出现 ClassCastException 运行时异常。<br>
<br>
前面介绍使用 Array 类来创建数组时，曾经看到如下代码：<br>
<p class="info-box">
	// 使用Array的newInstance方法来创建一个数组<br>
	Object arr = Array.newInstance(String.class, 10);</p>
对于上面的代码其实使用并不是非常方便，因为 newInstance() 方法返回的确实是一个 String[] 数组，而不是简单的 Object 对象。如果需要将 arr 对象当成 String[] 数组使用，则必须使用强制类型转换，但是这是不安全的操作。<br>
<br>
奇怪的是，Array 的 newInstance() 方法签名（方法签名由方法名称和参数列表组成）为如下形式：
<p class="info-box">
	public static Object newInstance(Class&lt;?&gt; componentType, int... dimensions)</p>
在这个方法签名中使用了 Class&lt;?&gt; 泛型，但并没有真正利用这个泛型。如果将该方法签名改为如下形式：
<p class="info-box">
	public static &lt;T&gt; T[] newInstance(Class&lt;T&gt; componentType, int length)</p>
这样就可以在调用该方法后无需强制类型转换了。不过，这个方法暂时只能创建一维数组，也就是不能利用可变个数的参数优势了。<br>
<br>
为了示范泛型的优势，可以对 Array 的 newInstance() 方法进行包装。
<div class="snippet-container" style="undefined;"><div class="sh_bright snippet-wrap"><div class="snippet-menu sh_sourceCode" style="display:none;"><pre><a class="snippet-copy sh_url" href="http://c.biancheng.net/view/vip_7082.html#" style="display: none;">复制</a><a class="snippet-text sh_url" href="http://c.biancheng.net/view/vip_7082.html#">纯文本</a><a class="snippet-window sh_url" href="http://c.biancheng.net/view/vip_7082.html#">复制</a></pre></div><pre class="java sh_java snippet-formatted sh_sourceCode"><ol class="snippet-num"><li><span class="sh_keyword">public</span> <span class="sh_keyword">class</span><span class="sh_normal"> </span><span class="sh_classname">CrazyitArray</span> <span class="sh_cbracket">{</span></li><li>    <span class="sh_comment">// 对Array的newInstance方法进行包装</span></li><li>    @<span class="sh_function">SuppressWarnings</span><span class="sh_symbol">(</span><span class="sh_string">"unchecked"</span><span class="sh_symbol">)</span></li><li>    <span class="sh_keyword">public</span> <span class="sh_keyword">static</span> <span class="sh_symbol">&lt;</span>T<span class="sh_symbol">&gt;</span> T<span class="sh_symbol">[]</span> <span class="sh_function">newInstance</span><span class="sh_symbol">(</span><span class="sh_usertype">Class&lt;T&gt;</span><span class="sh_normal"> </span>componentType<span class="sh_symbol">,</span> <span class="sh_type">int</span> length<span class="sh_symbol">)</span> <span class="sh_cbracket">{</span></li><li>        <span class="sh_keyword">return</span> <span class="sh_symbol">(</span>T<span class="sh_symbol">[])</span> Array<span class="sh_symbol">.</span><span class="sh_function">newInstance</span><span class="sh_symbol">(</span>componentType<span class="sh_symbol">,</span> length<span class="sh_symbol">);</span> </li><li>    <span class="sh_cbracket">}</span></li><li><span style="display:none;">&nbsp;</span></li><li>    <span class="sh_keyword">public</span> <span class="sh_keyword">static</span> <span class="sh_type">void</span> <span class="sh_function">main</span><span class="sh_symbol">(</span>String<span class="sh_symbol">[]</span> args<span class="sh_symbol">)</span> <span class="sh_cbracket">{</span></li><li>        <span class="sh_comment">// 使用 CrazyitArray 的 newInstance()创建一维数组</span></li><li>        String<span class="sh_symbol">[]</span> arr <span class="sh_symbol">=</span> CrazyitArray<span class="sh_symbol">.</span><span class="sh_function">newInstance</span><span class="sh_symbol">(</span>String<span class="sh_symbol">.</span><span class="sh_keyword">class</span><span class="sh_symbol">,</span> <span class="sh_number">10</span><span class="sh_symbol">);</span></li><li>        <span class="sh_comment">// 使用 CrazyitArray 的 newInstance()创建二维数组</span></li><li>        <span class="sh_comment">// 在这种情况下，只要设置数组元素的类型是int[]即可</span></li><li>        <span class="sh_type">int</span><span class="sh_symbol">[][]</span> intArr <span class="sh_symbol">=</span> CrazyitArray<span class="sh_symbol">.</span><span class="sh_function">newInstance</span><span class="sh_symbol">(</span><span class="sh_type">int</span><span class="sh_symbol">[].</span><span class="sh_keyword">class</span><span class="sh_symbol">,</span> <span class="sh_number">5</span><span class="sh_symbol">);</span></li><li>        arr<span class="sh_symbol">[</span><span class="sh_number">5</span><span class="sh_symbol">]</span> <span class="sh_symbol">=</span> <span class="sh_string">"C语言中文网Java教程"</span><span class="sh_symbol">;</span></li><li>        <span class="sh_comment">// intArr是二维数组，初始化该数组的第二个数组元素</span></li><li>        <span class="sh_comment">// 二维数组的元素必须是一维数组</span></li><li>        intArr<span class="sh_symbol">[</span><span class="sh_number">1</span><span class="sh_symbol">]</span> <span class="sh_symbol">=</span> <span class="sh_keyword">new</span> <span class="sh_type">int</span><span class="sh_symbol">[]</span><span class="sh_cbracket">{</span> <span class="sh_number">23</span><span class="sh_symbol">,</span> <span class="sh_number">12</span> <span class="sh_cbracket">}</span><span class="sh_symbol">;</span></li><li>        System<span class="sh_symbol">.</span>out<span class="sh_symbol">.</span><span class="sh_function">println</span><span class="sh_symbol">(</span>arr<span class="sh_symbol">[</span><span class="sh_number">5</span><span class="sh_symbol">]);</span></li><li>        System<span class="sh_symbol">.</span>out<span class="sh_symbol">.</span><span class="sh_function">println</span><span class="sh_symbol">(</span>intArr<span class="sh_symbol">[</span><span class="sh_number">1</span><span class="sh_symbol">][</span><span class="sh_number">1</span><span class="sh_symbol">]);</span></li><li>    <span class="sh_cbracket">}</span></li><li><span class="sh_cbracket">}</span></li></ol></pre><pre class="snippet-textonly sh_sourceCode" style="display:none;">public class CrazyitArray {
    // 对Array的newInstance方法进行包装
    @SuppressWarnings("unchecked")
    public static &lt;T&gt; T[] newInstance(Class&lt;T&gt; componentType, int length) {
        return (T[]) Array.newInstance(componentType, length); 
    }

    public static void main(String[] args) {
        // 使用 CrazyitArray 的 newInstance()创建一维数组
        String[] arr = CrazyitArray.newInstance(String.class, 10);
        // 使用 CrazyitArray 的 newInstance()创建二维数组
        // 在这种情况下，只要设置数组元素的类型是int[]即可
        int[][] intArr = CrazyitArray.newInstance(int[].class, 5);
        arr[5] = "C语言中文网Java教程";
        // intArr是二维数组，初始化该数组的第二个数组元素
        // 二维数组的元素必须是一维数组
        intArr[1] = new int[]{ 23, 12 };
        System.out.println(arr[5]);
        System.out.println(intArr[1][1]);
    }
}</pre></div></div>
上面程序中第 4、5、6、10 和 13 定义的 newInstance() 方法对 Array 类提供的 newInstance() 方法进行了包装，将方法签名改成了 <code>public static &lt;T&gt; T[] newInstance(Class&lt;T&gt; componentType, int length)</code>，这就保证程序通过该 newInstance() 方法创建数组时的返回值就是数组对象，而不是 Object 对象，从而避免了强制类型转换。<br>
<br>
提示：@SuppressWarnings("unchecked") 告诉编译器忽略 unchecked 警告信息，如使用 List，ArrayList 等未进行参数化产生的警告信息。程序在第 5 行代码处将会有一个 unchecked 编译警告，所以程序使用了 @SuppressWarnings 来抑制这个警告信息。
<h2>
	使用反射来获取泛型信息</h2>
通过指定类对应的 Class 对象，可以获得该类里包含的所有成员变量，不管该成员变量是使用 private 修饰，还是使用 public 修饰。获得了成员变量对应的 Field 对象后，就可以很容易地获得该成员变量的数据类型，即使用如下代码即可获得指定成员变量的类型。<br>
<p class="info-box">
	// 获取成员变量 f 的类型<br>
	Class&lt;?&gt; a = f.getType();</p>
但这种方式只对普通类型的成员变量有效。如果该成员变量的类型是有泛型类型的类型，如 Map&lt;String, Integer&gt;类型，则不能准确地得到该成员变量的泛型参数。<br>
<br>
为了获得指定成员变量的泛型类型，应先使用如下方法来获取该成员变量的泛型类型。
<p class="info-box">
	// 获得成员变量f的泛型类型<br>
	Type gType = f.getGenericType();</p>
然后将 Type 对象强制类型转换为 ParameterizedType 对象，ParameterizedType 代表被参数化的类型，也就是增加了泛型限制的类型。ParameterizedType 类提供了如下两个方法。<br>
<ul>
	<li>
		getRawType()：返回没有泛型信息的原始类型。</li>
	<li>
		getActualTypeArguments()：返回泛型参数的类型。</li>
</ul>
<br>
下面是一个获取泛型类型的完整程序。
<div class="snippet-container" style="undefined;"><div class="sh_bright snippet-wrap"><div class="snippet-menu sh_sourceCode" style="display:none;"><pre><a class="snippet-copy sh_url" href="http://c.biancheng.net/view/vip_7082.html#" style="display: none;">复制</a><a class="snippet-text sh_url" href="http://c.biancheng.net/view/vip_7082.html#">纯文本</a><a class="snippet-window sh_url" href="http://c.biancheng.net/view/vip_7082.html#">复制</a></pre></div><pre class="java sh_java snippet-formatted sh_sourceCode"><ol class="snippet-num"><li><span class="sh_keyword">public</span> <span class="sh_keyword">class</span><span class="sh_normal"> </span><span class="sh_classname">GenericTest</span> <span class="sh_cbracket">{</span></li><li>    <span class="sh_keyword">private</span> <span class="sh_usertype">Map&lt;String, Integer&gt;</span><span class="sh_normal"> </span>score<span class="sh_symbol">;</span></li><li><span style="display:none;">&nbsp;</span></li><li>    <span class="sh_keyword">public</span> <span class="sh_keyword">static</span> <span class="sh_type">void</span> <span class="sh_function">main</span><span class="sh_symbol">(</span>String<span class="sh_symbol">[]</span> args<span class="sh_symbol">)</span> <span class="sh_keyword">throws</span> Exception <span class="sh_cbracket">{</span></li><li>        <span class="sh_usertype">Class&lt;GenericTest&gt;</span><span class="sh_normal"> </span>clazz <span class="sh_symbol">=</span> GenericTest<span class="sh_symbol">.</span><span class="sh_keyword">class</span><span class="sh_symbol">;</span></li><li>        <span class="sh_usertype">Field</span><span class="sh_normal"> </span>f <span class="sh_symbol">=</span> clazz<span class="sh_symbol">.</span><span class="sh_function">getDeclaredField</span><span class="sh_symbol">(</span><span class="sh_string">"score"</span><span class="sh_symbol">);</span></li><li>        <span class="sh_comment">// 直接使用getType()取出类型只对普通类型的成员变量有效</span></li><li>        <span class="sh_usertype">Class&lt;?&gt;</span><span class="sh_normal"> </span>a <span class="sh_symbol">=</span> f<span class="sh_symbol">.</span><span class="sh_function">getType</span><span class="sh_symbol">();</span></li><li>        <span class="sh_comment">// 下面将看到仅输出java.util.Map</span></li><li>        System<span class="sh_symbol">.</span>out<span class="sh_symbol">.</span><span class="sh_function">println</span><span class="sh_symbol">(</span><span class="sh_string">"score 的类型是："</span> <span class="sh_symbol">+</span> a<span class="sh_symbol">);</span></li><li>        <span class="sh_comment">// 获得成员变量f的泛型类型</span></li><li>        <span class="sh_usertype">Type</span><span class="sh_normal"> </span>gType <span class="sh_symbol">=</span> f<span class="sh_symbol">.</span><span class="sh_function">getGenericType</span><span class="sh_symbol">();</span></li><li>        <span class="sh_comment">// 如果 gType 类型是 ParameterizedType对象</span></li><li>        <span class="sh_keyword">if</span> <span class="sh_symbol">(</span>gType <span class="sh_keyword">instanceof</span> ParameterizedType<span class="sh_symbol">)</span> <span class="sh_cbracket">{</span></li><li>            <span class="sh_comment">// 强制类型转换</span></li><li>            <span class="sh_usertype">ParameterizedType</span><span class="sh_normal"> </span>pType <span class="sh_symbol">=</span> <span class="sh_symbol">(</span>ParameterizedType<span class="sh_symbol">)</span> gType<span class="sh_symbol">;</span></li><li>            <span class="sh_comment">// 获取原始类型</span></li><li>            <span class="sh_usertype">Type</span><span class="sh_normal"> </span>rType <span class="sh_symbol">=</span> pType<span class="sh_symbol">.</span><span class="sh_function">getRawType</span><span class="sh_symbol">();</span></li><li>            System<span class="sh_symbol">.</span>out<span class="sh_symbol">.</span><span class="sh_function">println</span><span class="sh_symbol">(</span><span class="sh_string">"原始类型是："</span> <span class="sh_symbol">+</span> rType<span class="sh_symbol">);</span></li><li>            <span class="sh_comment">// 取得泛型类型的泛型参数</span></li><li>            Type<span class="sh_symbol">[]</span> tArgs <span class="sh_symbol">=</span> pType<span class="sh_symbol">.</span><span class="sh_function">getActualTypeArguments</span><span class="sh_symbol">();</span></li><li>            System<span class="sh_symbol">.</span>out<span class="sh_symbol">.</span><span class="sh_function">println</span><span class="sh_symbol">(</span><span class="sh_string">"泛型信息是:"</span><span class="sh_symbol">);</span></li><li>            <span class="sh_keyword">for</span> <span class="sh_symbol">(</span><span class="sh_type">int</span> i <span class="sh_symbol">=</span> <span class="sh_number">0</span><span class="sh_symbol">;</span> i <span class="sh_symbol">&lt;</span> tArgs<span class="sh_symbol">.</span>length<span class="sh_symbol">;</span> i<span class="sh_symbol">++)</span> <span class="sh_cbracket">{</span></li><li>                System<span class="sh_symbol">.</span>out<span class="sh_symbol">.</span><span class="sh_function">println</span><span class="sh_symbol">(</span><span class="sh_string">"第"</span> <span class="sh_symbol">+</span> i <span class="sh_symbol">+</span> <span class="sh_string">"个泛型类型是："</span> <span class="sh_symbol">+</span> tArgs<span class="sh_symbol">[</span>i<span class="sh_symbol">]);</span></li><li>            <span class="sh_cbracket">}</span></li><li>        <span class="sh_cbracket">}</span> <span class="sh_keyword">else</span> <span class="sh_cbracket">{</span></li><li>            System<span class="sh_symbol">.</span>out<span class="sh_symbol">.</span><span class="sh_function">println</span><span class="sh_symbol">(</span><span class="sh_string">"获取泛型类型出错!"</span><span class="sh_symbol">);</span></li><li>        <span class="sh_cbracket">}</span></li><li>    <span class="sh_cbracket">}</span></li><li><span class="sh_cbracket">}</span></li></ol></pre><pre class="snippet-textonly sh_sourceCode" style="display:none;">public class GenericTest {
    private Map&lt;String, Integer&gt; score;

    public static void main(String[] args) throws Exception {
        Class&lt;GenericTest&gt; clazz = GenericTest.class;
        Field f = clazz.getDeclaredField("score");
        // 直接使用getType()取出类型只对普通类型的成员变量有效
        Class&lt;?&gt; a = f.getType();
        // 下面将看到仅输出java.util.Map
        System.out.println("score 的类型是：" + a);
        // 获得成员变量f的泛型类型
        Type gType = f.getGenericType();
        // 如果 gType 类型是 ParameterizedType对象
        if (gType instanceof ParameterizedType) {
            // 强制类型转换
            ParameterizedType pType = (ParameterizedType) gType;
            // 获取原始类型
            Type rType = pType.getRawType();
            System.out.println("原始类型是：" + rType);
            // 取得泛型类型的泛型参数
            Type[] tArgs = pType.getActualTypeArguments();
            System.out.println("泛型信息是:");
            for (int i = 0; i &lt; tArgs.length; i++) {
                System.out.println("第" + i + "个泛型类型是：" + tArgs[i]);
            }
        } else {
            System.out.println("获取泛型类型出错!");
        }
    }
}</pre></div></div>
上面程序中的第 12、16、18 和 21 行代码就是取得泛型类型的关键代码。运行上面程序，将看到如下运行结果：<br>
<p class="info-box">
	score 的类型是：interface java.util.Map<br>
	原始类型是：interface java.util.Map<br>
	泛型信息是:<br>
	第0个泛型类型是：class java.lang.String<br>
	第1个泛型类型是：class java.lang.Integer</p>
从上面的运行结果可以看出，使用 getType() 方法只能获取普通类型的成员变量的数据类型。对于增加了泛型的成员变量，应该使用 getGenericType() 方法来取得其类型。<br>
<br>
提示：Type 也是 java.lang.reflect 包下的一个接口，该接口代表所有类型的公共高级接口，Class 是 Type 接口的实现类。Type 包括原始类型、参数化类型、数组类型、类型变量和基本类型等。</div>
			<div id="arc-append">
	<p>关注微信公众号「站长严长生」，在手机上阅读所有教程，随时随地都能学习。本公众号由<a class="col-link" href="http://c.biancheng.net/view/8092.html" target="_blank" rel="nofollow">C语言中文网站长</a>运营，每日更新，坚持原创，敢说真话，凡事有态度。</p>
	<p style="margin-top:12px; text-align:center;">
		<img width="180" src="./12.8Java高级应用之通过反射操作泛型_files/qrcode_weixueyuan_original.png" alt="魏雪原二维码"><br>
		<span class="col-green">微信扫描二维码关注公众号</span>
	</p>
</div>
<!-- <p>关注微信公众号「魏雪原」，跟着<a class="col-link" href="/view/8092.html" target="_blank">站长</a>一起学习，拒绝躺平，跳出内卷，用知识完成阶级跃升：</p>
	<ul>
		<li>每日更新，坚持原创，敢说真话，凡事有态度。</li>
		<li>编程+求职+创业+营销，既有硬知识，也有软技能。</li>
		<li>手机端阅读教程，随时随地都能学习。</li>
		<li>即将绑定网站部分功能，包括注册登录、找回密码、获取下载链接等。</li>
	</ul> -->
			<div class="pre-next-page clearfix">
                    <span class="pre left"><span class="icon">&lt;</span> <span class="text-brief text-brief-pre">上一页</span><a href="http://c.biancheng.net/view/vip_7083.html">Java高级应用之通过反射访问操作数组</a></span>
                    <span class="next right"><a href="http://c.biancheng.net/java/130/">Java输入/输出流</a><span class="text-brief text-brief-next">下一页</span> <span class="icon">&gt;</span></span>
                </div>
			<div id="ad-arc-bottom"></div>

<!-- <div id="ad-bottom-weixin" class="clearfix">
	<div class="left" style="width: 535px;">
		<p><span class="col-red">编程帮</span>，一个分享编程知识的公众号。跟着<a class="col-link" href="/cpp/about/author/" target="_blank">站长</a>一起学习，每天都有进步。</p>
		<p>通俗易懂，深入浅出，一篇文章只讲一个知识点。</p>
		<p>文章不深奥，不需要钻研，在公交、在地铁、在厕所都可以阅读，随时随地涨姿势。</p>
		<p>文章不涉及代码，不烧脑细胞，人人都可以学习。</p>
		<p>当你决定关注「编程帮」，你已然超越了90%的程序员！</p>
	</div>
	<div class="right" style="width: 150px;">
		<img width="150" src="/templets/new/images/erweima_biancheng.gif?v=1.6.72" alt="编程帮二维码" /><br />
		<span class="col-green">微信扫描二维码关注</span>
	</div>
</div> -->

<div id="nice-arcs" class="box-bottom">
	<h4>优秀文章</h4>
	<ul class="clearfix">
<li><a href="http://c.biancheng.net/view/424.html" title="C++ vector添加（增加）元素">C++ vector添加（增加）元素</a></li>
<li><a href="http://c.biancheng.net/view/1833.html" title="C语言字符串的输入和输出">C语言字符串的输入和输出</a></li>
<li><a href="http://c.biancheng.net/view/3054.html" title="C#/.NET BCL：基础类库">C#/.NET BCL：基础类库</a></li>
<li><a href="http://c.biancheng.net/view/3632.html" title="MapReduce编程实例：单词计数">MapReduce编程实例：单词计数</a></li>
<li><a href="http://c.biancheng.net/view/3638.html" title="汇编语言ENTER和LEAVE指令：创建和结束堆栈帧">汇编语言ENTER和LEAVE指令：创建和结束堆栈帧</a></li>
<li><a href="http://c.biancheng.net/view/5019.html" title="JSP JSTL &lt;sql:transaction&gt;标签：事务处理">JSP JSTL &lt;sql:transaction&gt;标签：事务处理</a></li>
<li><a href="http://c.biancheng.net/view/6880.html" title="营销型网站是什么？">营销型网站是什么？</a></li>
<li><a href="http://c.biancheng.net/view/6926.html" title="死链接（无效链接）是什么？">死链接（无效链接）是什么？</a></li>
<li><a href="http://c.biancheng.net/view/vip_7734.html" title="C++ STL标准库这么多排序函数，该如何选择？">C++ STL标准库这么多排序函数，该如何选择？</a></li>
<li><a href="http://c.biancheng.net/view/8012.html" title="PHP在图像上绘制文字">PHP在图像上绘制文字</a></li>
</ul>
</div>
		</div>
		
	</div>
</div>
<script type="text/javascript">
// 当前文章ID
window.arcIdRaw = 'a_' + 7082;
window.arcId = "4d99mUNP1P2+cD1Ty1d/pbqFW/d+UucgnZM4UGUK7HMI2/eX9P47yFmzlAA";
window.typeidChain = "107|79";
</script>
<div id="footer" class="clearfix">
	<div class="info left">
	<p>精美而实用的网站，分享优质编程教程，帮助有志青年。千锤百炼，只为大作；精益求精，处处斟酌；这种教程，看一眼就倾心。</p>
	<p>
		<a href="http://c.biancheng.net/view/8066.html" target="_blank" rel="nofollow">关于网站</a> <span>|</span>
		<a href="http://c.biancheng.net/view/8092.html" target="_blank" rel="nofollow">关于站长</a> <span>|</span>
		<a href="http://c.biancheng.net/view/8097.html" target="_blank" rel="nofollow">如何完成一部教程</a> <span>|</span>
		<a href="http://c.biancheng.net/view/8093.html" target="_blank" rel="nofollow">联系我们</a> <span>|</span>
		<a href="http://c.biancheng.net/sitemap/" target="_blank" rel="nofollow">网站地图</a>
	</p>
	<p>Copyright ©2012-2021 biancheng.net, <a href="http://www.beian.miit.gov.cn/" target="_blank" rel="nofollow" style="color:#666;">陕ICP备15000209号</a></p>
	</div>
	<img class="right" src="./12.8Java高级应用之通过反射操作泛型_files/logo_bottom.gif" alt="底部Logo">
	<span id="return-top"><b>↑</b></span>
</div>

<script type="text/javascript">
window.siteId = 4;
window.cmsTemplets = "/templets/new";
window.cmsTempletsVer = "1.6.72";
</script>

<script src="./12.8Java高级应用之通过反射操作泛型_files/jquery1.12.4.min.js.下载"></script>
<script src="./12.8Java高级应用之通过反射操作泛型_files/common.js.下载"></script>
<span style="display:none;"><script src="./12.8Java高级应用之通过反射操作泛型_files/z_stat.php" type="text/javascript" defer="defer" async="async"></script></span>

</body></html>